package com.ctim.web.util;

import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * The Class HttpTools.
 *
 */
public class HttpTools {
    private static Map<Long, Long> internalIpRange = new HashMap<Long, Long>();
    private static Map<Long, Long> trustedIpRange = new HashMap<Long, Long>();
    
    private HttpTools() {
    }

    /**
     * Host to long.
     *
     * @param ipAddress the ip address
     * @return the long
     */
    private static long hostToLong(String ipAddress) {
        long[] ip = new long[4];

        int position1 = ipAddress.indexOf(".");
        int position2 = ipAddress.indexOf(".", position1 + 1);
        int position3 = ipAddress.indexOf(".", position2 + 1);

        ip[0] = Long.parseLong(ipAddress.substring(0, position1));
        ip[1] = Long.parseLong(ipAddress.substring(position1 + 1, position2));
        ip[2] = Long.parseLong(ipAddress.substring(position2 + 1, position3));
        ip[3] = Long.parseLong(ipAddress.substring(position3 + 1));

        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
    }
    
    public static boolean isTrustedIp(String ip) {
        if (!isValidIp(ip)) {
            return false;
        }
        long currentIp = hostToLong(ip);
        
        Iterator<Entry<Long, Long>> it = trustedIpRange.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Long, Long> entry = it.next();
            if (entry.getKey() <= currentIp && currentIp <= entry.getValue()) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * Checks if is internal ip.
     *
     * @param ip the ip
     * @return true, if is internal ip
     */
    public static boolean isInternalIp(String ip) {
        if (!isValidIp(ip)) {
            return false;
        }
        long currentIp = hostToLong(ip);
        
        Iterator<Entry<Long, Long>> it = internalIpRange.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Long, Long> entry = it.next();
            if (entry.getKey() <= currentIp && currentIp <= entry.getValue()) {
                return true;
            }
        }
        
        return false;
    }
    
    public static boolean isValidIp(String ip) {
        if (StringUtils.isEmpty(ip)) {
            return false;
        }
        
        if (ip.matches("(\\d{1,3}\\.){3}\\d{1,3}")) {
            return true;
        }
        
        return false;
    }

    /**
     * Gets the http client ip.
     *
     * @param request the request
     * @return the http client ip
     */
    public static String getHttpClientIP(HttpServletRequest request) {
        String ip = getHttpClientIPs(request);
        
        if (StringUtils.isNotEmpty(ip)) {
            ip = ip.split(",")[0].trim();
        }
        
        return ip;
    }

    /**
     * Gets the http client i ps.
     *
     * @param request the request
     * @return the http client i ps
     */
    public static String getHttpClientIPs(HttpServletRequest request) {
        String ip = "EMPTY";

        if (request.getHeaders("X-Forwarded-For").hasMoreElements()) {
            ip = request.getHeaders("X-Forwarded-For").nextElement();
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        
        return ip.trim();
    }
}
